package com.samphanie.security.security.authorization;

import cn.hutool.core.collection.CollUtil;
import com.samphanie.security.config.IgnoreUrlsConfig;
import com.samphanie.security.security.component.DynamicSecurityFilter;
import com.samphanie.security.security.filter.AuthGlobalFilter;
import com.samphanie.security.security.filter.IgnoreUrlsRemoveJwtFilter;
import com.samphanie.security.security.handler.RestAuthenticationEntryPoint;
import com.samphanie.security.security.handler.RestfulAccessDeniedHandler;
import com.samphanie.security.security.properties.AuthConstants;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;

import java.util.List;


/**
 * @Author ZSY
 * @createTime 2021/3/13 14:27
 */
@Component
@RequiredArgsConstructor
@Order(Ordered.LOWEST_PRECEDENCE)
public class DefaultAuthorizeConfigProvider implements AuthorizeConfigProvider {

    private final IgnoreUrlsConfig ignoreUrlsConfig;
    private final RestfulAccessDeniedHandler restfulAccessDeniedHandler;
    private final RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Autowired(required = false)
    private DynamicSecurityFilter dynamicSecurityFilter;

    private final AuthGlobalFilter authGlobalFilter;
    private final IgnoreUrlsRemoveJwtFilter ignoreUrlsRemoveJwtFilter;

    /**
     * 返回的boolean表示配置中是否有针对anyRequest的配置。在整个授权配置中，应该有且仅有一个针对anyRequest的配置
     * 如果所有的实现都没有针对anyRequest的配置，系统会自动增加一个anyRequest().authenticated()的配置。
     * 如果有多个针对anyRequest的配置，则会抛出异常。
     *
     * @throws Exception 异常
     */
    @Override
    public boolean config(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) throws Exception {

        config.antMatchers(
                HttpMethod.OPTIONS,
                "/**"
        ).permitAll();

        config.antMatchers(
                HttpMethod.GET,
                "/error",
                "/doc.html",
                "/**/v3/api-docs/**",
                "/swagger-resources/**",
                "/actuator/**",
                "/druid/**",
                "/webjars/**",
                "/**/*.ico",
                "/**/*.js",
                "/**/*.css",
                "/**/*.jpg",
                "/**/*.jpeg",
                "/**/*.png",
                "/**/*.gif"
        ).permitAll();

        config
                // 自定义权限拒绝处理类
                .and()
                //        exceptionHandling -> exceptionHandling
                //                .authenticationEntryPoint(restAuthenticationEntryPoint)
                //                .accessDeniedHandler(restfulAccessDeniedHandler)
                .exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthenticationEntryPoint);

        List<String> urls = ignoreUrlsConfig.getUrls();
        if (CollUtil.isNotEmpty(urls)) {
            for (String url : ignoreUrlsConfig.getUrls()) {
                config.antMatchers(url).permitAll();
            }
        }

        // 对白名单路径，直接移除JWT请求头
        // http.addFilterBefore(ignoreUrlsRemoveJwtFilter, SecurityWebFiltersOrder.AUTHENTICATION);
        config.and()
                .addFilterBefore(ignoreUrlsRemoveJwtFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(authGlobalFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(dynamicSecurityFilter, FilterSecurityInterceptor.class);
        return false;
    }
}
